// BlVCamServerProxyDlg.h : header file
//

#if !defined(AFX_BlVCamServerProxyDLG_H__66945FE6_6A79_49D6_9BB3_8F589F2A4CC6__INCLUDED_)
#define AFX_BlVCamServerProxyDLG_H__66945FE6_6A79_49D6_9BB3_8F589F2A4CC6__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
 
/////////////////////////////////////////////////////////////////////////////
// CBlVCamServerProxyDlg dialog
#include "../Common/inc/BlAPI.h"
#include "../Common/inc/BlClass.h"

#include <winsock2.h>
#include <math.h>

#define  BUFFER_SIZE 1024
#define	 ServerConfigIniFile	"./ServerConfig.ini" 

typedef struct tag_BufferSocket
{
	SOCKET Socket;
	char *ReadPtr;
	char ReadBuf[BUFFER_SIZE];
	int ReadCount;
} BufferSocket;

class CBlVCamServerProxyDlg : public CDialog
{
	class CMyToolBar:public CToolBar
	{
	public:
		CMyToolBar(){}
		~CMyToolBar(){}
		void plInit(CWnd* pWnd,UINT id)
		{
			if(!Create(pWnd) || !LoadToolBar(IDR_TOOLBAR_MAIN))
			{
				TRACE0("Failed to Create Dialog Toolbar\n"); 
			}
			
			CRect rcClientOld; 
			CRect rcClientNew; 
			pWnd->GetClientRect(rcClientOld); 
			pWnd->RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0,reposQuery,rcClientNew);
			
			CPoint ptOffset(rcClientNew.left-rcClientOld.left,
				rcClientNew.top-rcClientOld.top);
			
			CRect rcChild;
			CWnd* pwndChild = pWnd->GetWindow(GW_CHILD); 
			while(pwndChild) 
			{
				pwndChild->GetWindowRect(rcChild);
				ScreenToClient(rcChild); 
				rcChild.OffsetRect(ptOffset); 
				pwndChild->MoveWindow(rcChild,FALSE); 
				pwndChild = pwndChild->GetNextWindow();
			}
			
			CRect rcWindow;
			pWnd->GetWindowRect(rcWindow); 
			rcWindow.right += rcClientOld.Width() - rcClientNew.Width(); 
			rcWindow.bottom += rcClientOld.Height() - rcClientNew.Height(); 
			pWnd->MoveWindow(rcWindow,FALSE);
			
			pWnd->RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0);
		}
	};

	class CMyDll
	{
	public:
		CMyDll(){
			char pluginPath[32];
	        GetPrivateProfileString("Plugin", "path", "B1/BlVSensor.dll", pluginPath, sizeof(pluginPath), ServerConfigIniFile);
			m_hModule = LoadLibrary(pluginPath);
		}
		~CMyDll(){
			if(m_hModule)
			{
				FreeLibrary (m_hModule);
				m_hModule = NULL;
			}
		} 
		BLSTATUS OnBlCallLibFun(HWND h,UINT m,WPARAM w,LPARAM l)
		{
			BLSTATUS r = prCallLibFun(h,m,w,l);
			return r;
		}
	private: 
		HMODULE		m_hModule;
		
		BLSTATUS pvCallLibFun(HWND h,char *szFun,UINT m,WPARAM w,LPARAM l)
		{
			BLSTATUS r = BL_STATUS_NOT_SUPPORT_INTERFACE; 
			
			if(NULL != m_hModule)
			{
				FARPROC pFunc = GetProcAddress(m_hModule, szFun);
				if (pFunc ) {
					r = (* (OnBLAPI *)pFunc)(h,m,w,l);   
				}
			}
			else
			{
				r = BL_STATUS_NOT_FOUND_LIBARY;
			}
			return r;
		}
		BLSTATUS prCallLibFun(HWND h,UINT m,WPARAM w,LPARAM l)
		{
			BLSTATUS r = BL_STATUS_NOT_SUPPORT_INTERFACE; 
			r = pvCallLibFun(h,"OnBlApi",m,w,l);
			return r;
		} 
	};

	class CVCamProxy
	{
#define SERVER_PORT 9096
		
	private:
		static CVCamProxy*     _pMyInstance;
		LPBYTE				   m_pDataBuffer;
		CBlVCamServerProxyDlg  *m_pParent;
		SOCKET m_serverSocket;
		BOOL   m_bWorkerThreadActive;
		
	public:
		CVCamProxy(CBlVCamServerProxyDlg *p):m_pDataBuffer(NULL),m_pParent(p){
			m_bWorkerThreadActive = TRUE;
		}
		~CVCamProxy(){
			if (m_pDataBuffer)
				delete []m_pDataBuffer;
		}
		static CVCamProxy* GetInstance(void* pParent=NULL)
		{		
			if ( _pMyInstance == NULL){
				_pMyInstance = new CVCamProxy((CBlVCamServerProxyDlg*)pParent);
			}
			return _pMyInstance;
		}
		
		static void ClearInstance()
		{
			if( _pMyInstance!=NULL ) delete _pMyInstance;
		}

		static int CALLBACK pvCallbackFunc(BL_CB_INF *pInfo)
		{
			int r = 0;
			CVCamProxy *pThis = (CVCamProxy*)pInfo->pCaller;
			BYTE *pBuffer = (BYTE*)pInfo->pParam;

			if (_pMyInstance->m_pDataBuffer == NULL)
			{
				_pMyInstance->m_pDataBuffer = new BYTE[300*300*3];
			}
			::memcpy(_pMyInstance->m_pDataBuffer, pBuffer, 300*300*3);
			
			return r;
		}

		BLSTATUS pl2Init(HWND h,UINT m, WPARAM w, LPARAM l)
		{
			BLSTATUS r					= BL_STATUS_NOT_SUPPORT_INTERFACE;
			BL_LPARAM_CONTEXT	c		= {0};
			c.m							= BL_WM_INIT;
			c.idFrom					= BL_ID_B1_03; //BlVCamServer
			c.idTo						= BL_ID_B1_ALL;
			c.LPARAM.CallBack.pFun		= pvCallbackFunc;
			c.LPARAM.CallBack.pParam	= this;
			sprintf(c.szVerify,"BEAUTIFULLOVER"); 
			
			m_pParent->m_MyDll.OnBlCallLibFun(h,c.m,w,(LPARAM)&c);

			return r;
		}
		
		void plWndProc(UINT m, WPARAM w, LPARAM l)
		{
			ptWndProc(m,w,l);
		} 
		
		int plStartMonitor(int nPort=SERVER_PORT)
		{
			WSADATA wsaData;
			SOCKADDR_IN serverAddr;
			
			int Ret;
			//Init Winsock Dll
			if((Ret = WSAStartup(MAKEWORD(2,2),&wsaData)) != 0)
			{
				TRACE("WSAStartup failed with error %d\n", Ret);
				return 0;
			}
			
			//Setup socket
			if((m_serverSocket = socket(AF_INET, SOCK_STREAM, 0))==INVALID_SOCKET)
			{
				TRACE("Create socket error\n");
				WSACleanup();
				return 0;
			}
			
			//Fill SOCKADDR_IN struct
			serverAddr.sin_family=AF_INET;
			serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);
			serverAddr.sin_port=htons(nPort);
			
			//Binding the server socket with IP and Port
			if(bind(m_serverSocket,(SOCKADDR *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
			{
				int err = WSAGetLastError();
				TRACE("Bind error:%d!\n",err);
				closesocket(m_serverSocket);
				WSACleanup();
				return 0;
			}
			
			if(listen(m_serverSocket,5) != 0)
			{
				closesocket(m_serverSocket);
				WSACleanup();
				return 0;
			}
			
			m_bWorkerThreadActive = TRUE;
			HANDLE hThreadWorker = ::CreateThread(NULL, 0, Worker, (LPVOID)this, 0, NULL);
			CloseHandle(hThreadWorker);
			
			return 0;
		}
		
		void plStopMonitor()
		{
			m_bWorkerThreadActive = FALSE;
			closesocket(m_serverSocket);
			WSACleanup();
		}
		
	private:
		
		void ptWndProc(UINT m, WPARAM w, LPARAM l)
		{
			int x = (int)(short)LOWORD(l);
			int y = (int)(short)HIWORD(l);
			switch(m)
			{ 
			case BL_WM_B1_0XB101:
				{					
					int nSize = (int)l;
					BYTE* pData = (BYTE*)w;
					

				}
				
				break;
			case WM_CHAR:
				break;
			case WM_LBUTTONDOWN:
				break;
			case WM_LBUTTONUP:
				break;
			case WM_MOUSEMOVE:
				break;
			case WM_SIZE:
				{ 
					CRect rt; 
					m_pParent->GetClientRect(&rt); 
					rt.top = rt.bottom - 20;  
				}
				break;
			case WM_COMMAND:
				{
					switch (LOWORD (w))
					{
					case ID_FILE_QUIT:
						{
							CVCamProxy::ClearInstance();
							PostQuitMessage (0); 
						}
					}
				}
				break ;
			}
		}
		
		static DWORD WINAPI Worker(LPVOID lpParameter)
		{
			HANDLE hThread = NULL;
			SOCKADDR_IN clientAddr;
			int clientAddrLen = sizeof(clientAddr);
            SOCKET newConnection;
			
			while(_pMyInstance->m_bWorkerThreadActive)
			{
				if((newConnection = accept(_pMyInstance->m_serverSocket,(sockaddr FAR*)&clientAddr,&clientAddrLen)) == INVALID_SOCKET)
				{
					continue;
				}
				
				hThread = ::CreateThread(NULL,0, RecvPorc,(LPVOID)&newConnection,0,NULL);
				CloseHandle(hThread);
			}
			
			closesocket(_pMyInstance->m_serverSocket);
			WSACleanup();
			
			TRACE("Worker Thread exit!");
			return 0;
		}
		
		static DWORD WINAPI RecvPorc(LPVOID lpParameter)
		{
			BufferSocket BufSock;
			BufSock.ReadCount = 0;
			BufSock.Socket = *((SOCKET *) lpParameter);
			
			_pMyInstance->ParseProtocol(BufSock);
			
			closesocket(BufSock.Socket);
			return 0;
		}
		
		int ReadCharFromBufferSocket(BufferSocket* pSock,char *ptr)
		{
			if(pSock->ReadCount <= 0)
			{
				pSock->ReadCount = recv(pSock->Socket,pSock->ReadBuf, BUFFER_SIZE,0);
				if(pSock->ReadCount <= 0)		// EOF or SOCKET_ERROR
					return pSock->ReadCount;
				
				pSock->ReadPtr = pSock->ReadBuf;
			}
			pSock->ReadCount--;
			*ptr = *pSock->ReadPtr++;
			return 1;
		}
		
		int	ReadFromBufferSocket(BufferSocket* pSock,char* szBuf,int nBufSize)
		{
			char c, *ptr;
			int n, rc;
			ptr = szBuf;
			for(n = 1; n < nBufSize; n++)
			{
				rc = ReadCharFromBufferSocket(pSock,&c);
				if(rc == 1)
				{
					*ptr++ = c;
					if(c == '\n')
						break;
				}
				else		// EOF or SOCKET_ERROR
				{
					if(n==1)  // NO data read
						return 0;
					else
						break;
				}
			}
			
			ptr--;
			*ptr = '\0';
			return n;
		}
		
		int WriteSocket(SOCKET s,char FAR *buf,int n)
		{
			int count = 0;
			int sc;
			while(count < n)
			{
				sc = send(s,buf + count,n - count,0);
				if(sc < 0)
					return sc;
				if(sc == 0)
					Sleep(100);
				count += sc;
			}
			return count;
		}
		
		void ParseProtocol(BufferSocket BufSock)
		{
			char szBuffer[BUFFER_SIZE], *NoMessage = "Sorry,We can't find the BLWM message!";
			int Ret = ReadFromBufferSocket(&BufSock , szBuffer , BUFFER_SIZE);
			szBuffer[Ret-2]='\0';
			
			DWORD *pDWord = (DWORD*)szBuffer;
			BLWM V;
			memcpy(&V, pDWord, sizeof(DWORD));
			
			switch(V){
			case BL_WM_B1_0XB101:
				{
					int nSize=300;
					char* pNew = new char[nSize*nSize*3];
					::memcpy(pNew, m_pDataBuffer, nSize*nSize*3);
					
					if((Ret = WriteSocket(BufSock.Socket, pNew, nSize*nSize*3)) < 0 ){
						TRACE("Send failed. You can try again!\n");
					}
					delete []pNew;
				} 
				break;
			case BL_WM_CMD_B0_2_B1_01:
				break;
			default:
				{
					if((Ret = WriteSocket(BufSock.Socket, NoMessage,strlen(NoMessage))) < 0 )
						TRACE("Send failed.");
				}
				break;
			}
			return;
		}
		
	};
	// Construction
public:
	CBlVCamServerProxyDlg(CWnd* pParent = NULL);	// standard constructor
	CMyToolBar				m_myToolBar;

	
	// Dialog Data
	//{{AFX_DATA(CBlVCamServerProxyDlg)
	enum { IDD = IDD_BlVCamServerProxy_DIALOG };
	//}}AFX_DATA
	
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CBlVCamServerProxyDlg)
	public:
	virtual BOOL PreTranslateMessage(MSG* pMsg);
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support
	virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
	//}}AFX_VIRTUAL
	
	// Implementation
protected:
	HICON m_hIcon;
	
	// Generated message map functions
	//{{AFX_MSG(CBlVCamServerProxyDlg)
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	afx_msg void OnBtnStart();
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
private: 
public:
	CMyDll	 m_MyDll;
		
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_BlVCamServerProxyDLG_H__66945FE6_6A79_49D6_9BB3_8F589F2A4CC6__INCLUDED_)
